﻿#define _CRT_SECURE_NO_WARNINGS 1


#include<stdio.h>



//1.一些预定义符号
//int main()
//{
//	printf("%s\n", __FILE__);//进⾏编译的源⽂件
//	printf("%d\n", __LINE__);//⽂件当前的⾏号
//	printf("%s\n", __DATE__);//⽂件被编译的⽇期
//	printf("%s\n", __TIME__);//⽂件被编译的时间
//	//printf("%s\n", __STDC__);//error，VS2022编译环境不支持STDC
//
//	return 0;
//}




//2.#define定义常量
#define MAX 100

#define MIN 1;
//如果在定义内容后加了个‘;’号，那么输入MIN就相当于输入"1;"，下面main函数里有举例

#define DEBUG_PRINT printf("FILE:%s\n\
LINE:%d\n\
DATE:%s\n\
TIME:%s\n\
",__FILE__,__LINE__,__DATE__,__TIME__)
//当定义内容过长可以写成几行，不过要在行尾加上一个‘\’(除了最后一行都加)，这样这几行就相当于一行了
//\ 前 和 后 有空格的话就相当于打印内容里有空格了

//int main()
//{
//	DEBUG_PRINT;
//	int min = MIN
//	//这里不需要在MIN后加上个;号，因为定义内容里已经存在
//	return 0;
//}




//3.#define定义宏(函数中也可以用哦，不过就应该是局部变量了)
#define DIV_1(x)  x  *  x//不严谨的
#define DIV_2(x) (x) * (x)//严谨的
//左边定义宏的名字要紧贴哦，不可以写成ADD_true (x)类似的形式，不然(x)会被判定为与后面一体
//int main()
//{
//	int a = 2;
//	printf("%d\n", DIV_1(a));//4	， a * a = 2 * 2 =4
//	printf("%d\n", DIV_2(a));//4	，(a)*(a)=(2)*(2)=4
//	printf("%d\n", DIV_1(a+1));//5	， a+1 * a+1 = 2+1 * 2+1 =5
//	printf("%d\n", DIV_2(a+1));//9	，(a+1)*(a+1)=(2+1)*(2+1)=9
//	//宏定义这一点需要注意，在编译过程中，它会直接将定义的宏转变为我们定义的形式
//	//然后再进行运算等，如下举例：
//	//printf("%d\n",  a+1 * a+1 );
//	//printf("%d\n", (a+1)*(a+1));
//	//所以定义宏的过程中要多加括号
//	return 0;
//}




//4.带有副作用的宏参数
//写一个宏，求2个数的大小
//#define MAX(x,y) ((x)>(y)?(x):(y))
//int main()
//{
//	int a = 1;
//	int b = 2;
//	int c = MAX(a++, b++);
//	//相当于int c = ((a++)>(b++)?(a++):(b++));
//	//后置++，先比较a b大小，b大，否，选b++
//	//a++,b++后c=b++，后置++，c=b后b++
//	//总的来说就是a=a+1 b=b+2 c=b+1
//	printf("a=%d b=%d c=%d", a, b, c);//a=2 b=4 c=3
//	//明显这不是我们最初想要的结果，预期应为a=1 b=2 c=2
//	//这里就体现了宏定义与函数的不同
//	//图简便在某些情况下可以使用宏定义，图稳定还是用函数
//		//当用函数时就不同了，它会先将我们传入的参数进行计算得到具体数据再传入，
//		//而不是直接将参数传入再进行计算
//	return 0;
//}




//5.宏替换的规则
//不递归，不定义字符串(了解就行，写的时候谁用这个定义递归和字符串啊)
//具体替换过程大概就是那样了(上面提了一下)
//6.宏与函数的对比
//也就……，看课件
//宏能做到而函数做不到的一个重要操作：
//#define	Malloc(n,type) (type*)malloc(n*sizeof(type))
//int main()
//{
//	int* p1 = Malloc(5, int);
//	int* p2 = Malloc(5, char);
//	int* p3 = Malloc(5, float);
//	return 0;
//}//就是这样，对于数据类型的定义，使用宏定义就可做到更改




//7.#和##
//int main()
//{
//	/*printf("*****************\n\
//*****************\n\
//*****************\n\
//*****************\n\
//*****************\n\
//*****************\n\
//*****************\n\
//");*/
////这里试用一下\的效果
//
//	printf("hello "   "world");//相当于"hello world"，两个双引号之间的空格不会计入
//					//这里测试下，方便下面操作的理解
//	return 0;
//}

//#的用途之一
#define PRINT_A1(n) printf("There are %d apples\n",n)
#define PRINT_A2(n) printf("There are " #n " apples\n")//这里#n就相当于"n"了，不过n是被替换后的n
//int main()
//{
//	PRINT_A1(33);
//	PRINT_A2(33);
//	return 0;
//}

//##的用途之一，对注释方法与\操作符的进一步理解
#define TYPE_MAX(type)\
type type##_max(type x, type y)/*这里##起到连接作用，先将type替换再与_max连接成type_max的形式*/\
{\
	return x > y ? x : y;\
}
//不可以在中间注释哦，会报错，具体原因我认为：以上define后半部分是连着的一个整体相当于
//*一行*，你想一想你写注释是在一行代码中间插入是不是很容易报错
//(//这种注释方法不可行，但可以用/* */这种注释方法，而且还要使用在合适地方，具体见上)
	//总之就是看做一行，你想一下在一行中/**/这种注释要怎么添加才不会改变原数据执行内容
	//中间要注意\操作符的穿插，
TYPE_MAX(int);
TYPE_MAX(float);
//由于是定义函数，不可以直接在main函数内执行，毕竟有函数嵌套，但是没有函数内写函数对吧>_<
//int main()
//{
//	int a = int_max(1, 2);//没报错说明有int_max函数
//	float b = float_max(1.1f, 2.1f);
//	printf("%d %.1f", a, b);//2 2.1
//	return 0;
//}




//8.命名约定
//把宏名全部⼤写
//函数名不要全部⼤写
//*可以看做程序员编写代码的一种习惯，方便记忆
//9.undef
//这条指令⽤于移除⼀个宏定义，对于不想要的宏定义就可以使用这条指令移除
#undef MAX
//#define MAX 100
//int main()
//{
//	int a = MAX;//这里会报错，表示未定义标识符MAX，说明移除成功
//	return 0;
//}




//10.命令行定义
//#define ARRAY_SIZE 5 //这就是命令行啦
//int main()
//{
//	int array[ARRAY_SIZE];
//	int i = 0;
//	for (i = 0; i < ARRAY_SIZE; i++)
//	{
//		array[i] = i;
//	}
//	for (i = 0; i < ARRAY_SIZE; i++)
//	{
//		printf("%d ", array[i]);
//	}
//	printf("\n");
//	return 0;
//}
//就是说ARRAY_SIZE的值可以随时修改，很方便，想要小点的数组只用修改一个数据就全都修改了




//11.条件编译，跟那个if else差不多，不过多了个endif表示结尾
//基本表示方法
#if 0
#elif 1
#else 2
#endif

//举例
//#define A1 0
//#if A1==1
//int main()
//{
//	printf("1");//挺高级的，不符合条件的部分自动淡化
//}
//#elif A1==2
//int main()
//{
//	printf("2");
//}
//#else
//int main()
//{
//	printf("？");//这里符合条件的部分照常运行
//}
//#endif

//一种注释类似的用法
#if 0
void test1()
{
	printf("**********\n");
}
void test2()
{
	printf("**********\n");
}
void test3()
{
	printf("**********\n");
}
void test4()
{
	printf("**********\n");
}
void test5()
{
	printf("**********\n");
}
int main()
{
	test1();
	test2();
	test3();
	test4();
	test5();
	return 0;
}
#endif
//就像这样一段有点长的代码想要注释挺麻烦就可以用#if和#endif使其失去功效

//defined(x)的应用，如果x以被定义就返回真，否则返回假
//#define MAX 1000
//int main()
//{
////#define TIAN 5//这种宏定义也可以在函数中使用
////	printf("%d\n", TIAN);
//#if defined(MAX)
//	printf("hehe\n");
//#else
//	printf("haha\n");
//#endif
////由此课件#if和#endif在函数中也是可以使用，函数中也能用来注释部分代码 
//	return 0;
//}




//12.头文件的包含
//#include<stdio.h>
//#include"add.h"
//主要就是<>和""的区别
//如果是""那么编译器运行时就会先去当前文件所在文件夹取(当前工作目录)寻找文件，找不到再去标准头文件库去寻找
//而如果是<>那么就会直接去标准头文件库寻找文件(更省时高效，也没提升多少-_-)
//
//总结：如果你调的是头文件库已有的头文件就直接用<>
//		如果你调用的是自己创建的头文件就用""包含
//

//#include"add.h"//明显重复会导致：
//#include"add.h"//编译器遇到包含头文件时会将这个头文件包含的所有内容重新编译一遍
//#include"add.h"//就会导致运行效率过慢
//#include"add.h"
//这种情况可以使用#pragma once//同一个头文件包含只运行一次




//








